package com.caijg.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.caijg.exception.CustomException;
import com.caijg.mapper.UserMapper;
import com.caijg.model.dto.LoginDTO;
import com.caijg.model.dto.PasswordDTO;
import com.caijg.model.dto.RegisterDTO;
import com.caijg.model.entity.User;
import com.caijg.model.vo.resp.LoginVO;
import com.caijg.model.vo.resp.Result;
import com.caijg.service.IUserService;
import com.caijg.utils.EmailUtil;
import com.caijg.utils.UserContext;
import jakarta.mail.MessagingException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

import static com.caijg.constant.CommonConstant.LOGIN_USER_TTL;
import static com.caijg.constant.CommonConstant.TOKEN_PREFIX;

/**
 * 用户表 服务实现类
 *
 * @author caijg
 * @since 2024-12-26
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final EmailUtil emailUtil;
    private final StringRedisTemplate redisTemplate;

    @Override
    public Result sendEmailCode(RegisterDTO registerDTO) {
        // 1.生成随机六位验证码
        String code = RandomUtil.randomNumbers(6);
        // 2.发送验证码到邮箱
        String email = registerDTO.getEmail();
        try {
            emailUtil.sendVerificationCode(email, code);
        } catch (MessagingException e) {
            throw new CustomException("验证码发送失败, 请重试", 500);
        }
        // 3.保存验证码到Redis
        redisTemplate.opsForValue().set("emailVerify:" + email,
                code, 300, TimeUnit.SECONDS);
        // 4.返回结果
        return Result.success();
    }

    @Override
    public Result register(RegisterDTO registerDTO) {
        // 1.从Redis中获取验证码
        String code = redisTemplate.opsForValue().get("emailVerify:" + registerDTO.getEmail());
        // 2.校验验证码
        if (code == null || !code.equals(registerDTO.getCode())) {
            throw new CustomException("验证码错误", 400);
        }
        // 3.清除Redis中的验证码
        redisTemplate.delete("emailVerify:" + registerDTO.getEmail());
        // 4.检查该邮箱是否已注册
        User user = this.query().eq("email", registerDTO.getEmail()).one();
        if (user != null) {
            throw new CustomException("该邮箱已注册", 400);
        }
        // 5.注册用户
        User newUser = User.builder()
                // 默认头像
                .avatar("https://cjg-sky-take-out.oss-cn-beijing.aliyuncs.com/%E5%A4%B4%E5%83%8F%20%E5%A5%B3%E5%AD%A9.png")
                .email(registerDTO.getEmail())
                .password(SecureUtil.md5(registerDTO.getPassword()))
                .nickname("新用户" + RandomUtil.randomNumbers(5))
                .createTime(LocalDateTime.now())
                .build();
        this.save(newUser);

        // 6.返回结果
        return Result.success();
    }

    @Override
    public Result login(LoginDTO loginDTO) {
        // 1.检查是否存在该用户
        User user = this.query().eq("email", loginDTO.getEmail()).one();
        if (user == null) {
            throw new CustomException("用户不存在，请注册", 400);
        }
        // 2.校验密码
        if (!SecureUtil.md5(loginDTO.getPassword()).equals(user.getPassword())) {
            throw new CustomException("密码错误", 400);
        }

        if (user.getState() == 0) {
            throw new CustomException("该用户已被禁用", 400);
        }
        // 3.验证成功，生成token
        // String token = JwtUtils.createToken(user.getId());
        // 制作token
        String token = IdUtil.fastSimpleUUID();
        // 存入redis
        redisTemplate.opsForValue()
                .set(TOKEN_PREFIX + token
                        , user.getId().toString()
                        , LOGIN_USER_TTL, TimeUnit.HOURS);
        // 4.封装VO
        LoginVO loginVO = LoginVO.builder()
                .id(user.getId())
                .email(user.getEmail())
                .nickname(user.getNickname())
                .avatar(user.getAvatar())
                .token(token)
                .age(user.getAge())
                .gender(user.getGender())
                .createTime(user.getCreateTime())
                .build();

        // 5.返回结果
        return Result.success(loginVO);
    }

    @Override
    public Result updateProfile(User user) {
        // 1.更新用户信息
        user.setUpdateTime(LocalDateTime.now());
        this.updateById(user);
        // 2.返回结果
        return Result.success();
    }

    @Override
    public Result changePassword(PasswordDTO passwordDTO) {
        // 1.检查旧密码是否正确
        User user = this.getById(UserContext.getUid());
        if (!SecureUtil.md5(passwordDTO.getOldPassword()).equals(user.getPassword())) {
            throw new CustomException("旧密码错误", 400);
        }
        // 2.更新密码
        user.setPassword(SecureUtil.md5(passwordDTO.getNewPassword()));
        this.updateById(user);
        // 3.返回结果
        return Result.success();
    }

    @Override
    public Result logout(HttpServletRequest request) {
        // 1.获取用户携带的token
        String token = request.getHeader("Authorization");

        // 2.删除redis中对应的token
        redisTemplate.delete(TOKEN_PREFIX + token);

        // 3.返回结果
        return Result.success();
    }
}